from django.db import models
from rest_framework import serializers

from field.models import Address, TreeSpecies


# Create your models here.
# 样木信息
class Tree(models.Model):
    id = models.AutoField(primary_key=True)
    address = models.ForeignKey(Address, on_delete=models.PROTECT, verbose_name='样木位置')
    X = models.FloatField(null=True, blank=True, verbose_name='坐标X')
    Y = models.FloatField(null=True, blank=True, verbose_name='坐标Y')
    year = models.IntegerField(null=True, blank=True, verbose_name='造林年度')
    treeSpecies = models.ForeignKey(TreeSpecies, on_delete=models.PROTECT, verbose_name='树种')
    number = models.IntegerField(null=False, blank=False, verbose_name='样木编号')
    TH = models.FloatField(null=True, blank=True, verbose_name='树高')
    DBH = models.FloatField(null=True, blank=True, verbose_name='胸径')
    DC = models.FloatField(null=True, blank=True, verbose_name='径阶(DBH-C)')
    # volume = models.FloatField(null=True, blank=True, verbose_name='材积')
    HFLB = models.FloatField(null=True, blank=True, verbose_name='枝下高(Height to First Live Branch)')
    CW_SN = models.FloatField(null=True, blank=True, verbose_name='Crown Width 冠幅-南北')
    CW_EW = models.FloatField(null=True, blank=True, verbose_name='Crown Width 冠幅-东西')

    remark = models.CharField(max_length=500, null=True, verbose_name="备注")

    class Meta:
        db_table = 'tree'
        ordering = ['address__city', 'address__name', 'treeSpecies__name', 'number']


class TreeSerializer(serializers.ModelSerializer):
    address = serializers.IntegerField(source='address.id')
    address_city = serializers.StringRelatedField(source='address.city')
    address_name = serializers.StringRelatedField(source='address.name')
    treeSpecies = serializers.IntegerField(source='treeSpecies.id')
    treeSpecies_name = serializers.StringRelatedField(source='treeSpecies.name')
    tree_num = serializers.SerializerMethodField('get_tree_num')

    class Meta:
        model = Tree
        fields = '__all__'

    def get_tree_num(self, obj):
        # 拼接地址、树种和样木编号
        address = obj.address.id if obj.address else ''
        treeSpecies = obj.treeSpecies.id if obj.treeSpecies else ''
        number = obj.number if obj.number else ''

        return f"{address}-{treeSpecies}-{number}"


# 样木直径
class TreeDia(models.Model):
    id = models.AutoField(primary_key=True)
    tree = models.ForeignKey(Tree, on_delete=models.PROTECT, verbose_name='样木')
    part = models.CharField(max_length=100, null=False, verbose_name='位置')
    p0 = models.FloatField(null=True, verbose_name='0根颈处')
    p05 = models.FloatField(null=True, verbose_name='0.5/10处')
    p1 = models.FloatField(null=True, verbose_name='1/10处')
    p2 = models.FloatField(null=True, verbose_name='2/10处')
    p3 = models.FloatField(null=True, verbose_name='3/10处')
    p4 = models.FloatField(null=True, verbose_name='4/10处')
    p5 = models.FloatField(null=True, verbose_name='5/10处')
    p6 = models.FloatField(null=True, verbose_name='6/10处')
    p7 = models.FloatField(null=True, verbose_name='7/10处')
    p8 = models.FloatField(null=True, verbose_name='8/10处')
    p9 = models.FloatField(null=True, verbose_name='9/10处')
    volume = models.FloatField(null=True, verbose_name='树干材积/m3')

    remark = models.CharField(max_length=500, null=True, verbose_name="备注")

    class Meta:
        db_table = 'tree_dia'
        ordering = ['tree_id', 'part']


class TreeDiaSerializer(serializers.ModelSerializer):
    TH = serializers.FloatField(source='tree.TH')

    class Meta:
        model = TreeDia
        fields = '__all__'

    # 重写 to_representation 方法，实现保留两位小数
    def to_representation(self, instance):
        data = super().to_representation(instance)
        # 定义需要保留两位小数的字段列表
        float_fields = ['volume', 'p0', 'p05', 'p1', 'p2', 'p3', 'p4', 'p5', 'p6', 'p7', 'p8', 'p9']
        for field in float_fields:
            if data.get(field) is not None:
                try:
                    data[field] = round(float(data[field]), 2)
                except (TypeError, ValueError):
                    # 处理转换异常，保持原值
                    pass
        return data


# 样木鲜重FW
class TreeFW(models.Model):
    id = models.AutoField(primary_key=True)
    tree = models.ForeignKey(Tree, on_delete=models.PROTECT, verbose_name='样木')

    crownT = models.FloatField(null=True, verbose_name='树冠鲜重-上')
    crownC = models.FloatField(null=True, verbose_name='树冠鲜重-中')
    crownB = models.FloatField(null=True, verbose_name='树冠鲜重-下')

    trunkT = models.FloatField(null=True, verbose_name='树干鲜重-上')
    trunkC = models.FloatField(null=True, verbose_name='树干鲜重-中')
    trunkB = models.FloatField(null=True, verbose_name='树干鲜重-下')

    branchT = models.FloatField(null=True, verbose_name='树枝鲜重-上')
    branchC = models.FloatField(null=True, verbose_name='树枝鲜重-中')
    branchB = models.FloatField(null=True, verbose_name='树枝鲜重-下')

    leafT = models.FloatField(null=True, verbose_name='叶鲜重-上')
    leafC = models.FloatField(null=True, verbose_name='叶鲜重-中')
    leafB = models.FloatField(null=True, verbose_name='叶鲜重-下')

    rhizome = models.FloatField(null=True, verbose_name='根鲜重-根茎')
    root_large = models.FloatField(null=True, verbose_name='根鲜重-粗根')
    root_fine = models.FloatField(null=True, verbose_name='根鲜重-细根')

    remark = models.CharField(max_length=500, null=True, verbose_name="备注")

    class Meta:
        db_table = 'tree_fw'
        ordering = ['tree_id']

    def save(self, *args, **kwargs):
        """在保存时对所有浮点字段进行四舍五入"""
        float_fields = [
            'crownT', 'crownC', 'crownB',
            'trunkT', 'trunkC', 'trunkB',
            'branchT', 'branchC', 'branchB',
            'leafT', 'leafC', 'leafB',
            'rhizome', 'root_large', 'root_fine'
        ]
        for field in float_fields:
            value = getattr(self, field)
            if value is not None:
                # 四舍五入到两位小数
                setattr(self, field, round(value, 2))
        super().save(*args, **kwargs)


class TreeFWSerializer(serializers.ModelSerializer):
    crown = serializers.SerializerMethodField()  # 树冠鲜重
    trunk = serializers.SerializerMethodField()  # 树干鲜重
    branch = serializers.SerializerMethodField()  # 树枝鲜重
    leaf = serializers.SerializerMethodField()  # 叶鲜重
    root = serializers.SerializerMethodField()  # 根鲜重

    weight = serializers.SerializerMethodField()  # 总重量
    ground = serializers.SerializerMethodField()  # 地上鲜重

    # 根茎比%/湿
    root_ratio = serializers.SerializerMethodField()

    # 根茎比/干

    class Meta:
        model = TreeFW
        fields = '__all__'

    def get_crown(self, obj):
        """计算树冠总鲜重"""
        return round((obj.crownT or 0) + (obj.crownC or 0) + (obj.crownB or 0), 2)

    def get_trunk(self, obj):
        """计算树干总鲜重"""
        return round((obj.trunkT or 0) + (obj.trunkC or 0) + (obj.trunkB or 0), 2)

    def get_branch(self, obj):
        """计算树枝总鲜重"""
        return round((obj.branchT or 0) + (obj.branchC or 0) + (obj.branchB or 0), 2)

    def get_leaf(self, obj):
        """计算叶总鲜重"""
        return round((obj.leafT or 0) + (obj.leafC or 0) + (obj.leafB or 0), 2)

    def get_root(self, obj):
        """计算根总鲜重"""
        if obj.rhizome is None and obj.root_large is None and obj.root_fine is None:
            return None
        return round((obj.rhizome or 0) + (obj.root_large or 0) + (obj.root_fine or 0), 2)

    def get_weight(self, obj):
        """计算 weight = crown + trunk + root"""
        crown = self.get_crown(obj)
        trunk = self.get_trunk(obj)
        root = self.get_root(obj)
        if root is None:
            return round(crown + trunk, 2)
        return round(crown + trunk + root, 2)

    def get_ground(self, obj):
        """计算 ground = crown + trunk"""
        crown = self.get_crown(obj)
        trunk = self.get_trunk(obj)
        return round(crown + trunk, 2)

    def get_root_ratio(self, obj):
        """计算根茎比%/湿"""
        root = self.get_root(obj)
        ground = self.get_ground(obj)
        if root is None or root == 0:
            return None
        if ground == 0 or ground is None:
            return 0
        return round(root / ground * 100, 2)


# 样木干重DW
class TreeDW(models.Model):
    id = models.AutoField(primary_key=True)
    tree = models.ForeignKey(Tree, on_delete=models.PROTECT, verbose_name='样木')

    trunkT = models.FloatField(null=True, verbose_name='树干干重-上')
    trunkC = models.FloatField(null=True, verbose_name='树干干重-中')
    trunkB = models.FloatField(null=True, verbose_name='树干干重-下')

    barkT = models.FloatField(null=True, verbose_name='皮干重-上')
    barkC = models.FloatField(null=True, verbose_name='皮干重-中')
    barkB = models.FloatField(null=True, verbose_name='皮干重-下')

    branchT = models.FloatField(null=True, verbose_name='树枝干重-上')
    branchC = models.FloatField(null=True, verbose_name='树枝干重-中')
    branchB = models.FloatField(null=True, verbose_name='树枝干重-下')

    leafT = models.FloatField(null=True, verbose_name='叶干重-上')
    leafC = models.FloatField(null=True, verbose_name='叶干重-中')
    leafB = models.FloatField(null=True, verbose_name='叶干重-下')

    rhizome = models.FloatField(null=True, verbose_name='根干重-根茎')
    root_large = models.FloatField(null=True, verbose_name='根干重-粗根')
    root_fine = models.FloatField(null=True, verbose_name='根干重-细根')

    remark = models.CharField(max_length=500, null=True, verbose_name="备注")

    class Meta:
        db_table = 'tree_dw'
        ordering = ['tree_id']

    def save(self, *args, **kwargs):
        """在保存时对所有浮点字段进行四舍五入"""
        float_fields = [
            'barkT', 'barkC', 'barkB',
            'trunkT', 'trunkC', 'trunkB',
            'branchT', 'branchC', 'branchB',
            'leafT', 'leafC', 'leafB',
            'rhizome', 'root_large', 'root_fine'
        ]
        for field in float_fields:
            value = getattr(self, field)
            if value is not None:
                # 四舍五入到两位小数
                setattr(self, field, round(value, 2))
        super().save(*args, **kwargs)


class TreeDWSerializer(serializers.ModelSerializer):
    bark = serializers.SerializerMethodField()  # 皮干重
    trunk = serializers.SerializerMethodField()  # 树干干重
    branch = serializers.SerializerMethodField()  # 树枝干重
    leaf = serializers.SerializerMethodField()  # 叶干重
    root = serializers.SerializerMethodField()  # 根干重

    weight = serializers.SerializerMethodField()  # 总重量
    ground = serializers.SerializerMethodField()  # 地上干重

    # 根茎比%/湿
    root_ratio = serializers.SerializerMethodField()

    # 根茎比/干

    class Meta:
        model = TreeDW
        fields = '__all__'

    def get_bark(self, obj):
        """计算树冠总干重"""
        return round((obj.barkT or 0) + (obj.barkC or 0) + (obj.barkB or 0), 2)

    def get_trunk(self, obj):
        """计算树干总干重"""
        return round((obj.trunkT or 0) + (obj.trunkC or 0) + (obj.trunkB or 0), 2)

    def get_branch(self, obj):
        """计算树枝总干重"""
        return round((obj.branchT or 0) + (obj.branchC or 0) + (obj.branchB or 0), 2)

    def get_leaf(self, obj):
        """计算叶总干重"""
        return round((obj.leafT or 0) + (obj.leafC or 0) + (obj.leafB or 0), 2)

    def get_root(self, obj):
        """计算根总干重"""
        if obj.rhizome is None and obj.root_large is None and obj.root_fine is None:
            return None
        return round((obj.rhizome or 0) + (obj.root_large or 0) + (obj.root_fine or 0), 2)

    def get_weight(self, obj):
        """计算 weight = bark + trunk + root"""
        bark = self.get_bark(obj)
        trunk = self.get_trunk(obj)
        root = self.get_root(obj)
        if root is None:
            return round(bark + trunk, 2)
        return round(bark + trunk + root, 2)

    def get_ground(self, obj):
        """计算 ground = bark + trunk"""
        bark = self.get_bark(obj)
        trunk = self.get_trunk(obj)
        return round(bark + trunk, 2)

    def get_root_ratio(self, obj):
        """计算根茎比%/湿"""
        root = self.get_root(obj)
        ground = self.get_ground(obj)
        if root is None or root == 0:
            return None
        if ground == 0 or ground is None:
            return 0
        return round(root / ground * 100, 2)


# 样木器官样品记录
class TreeSample(models.Model):
    id = models.AutoField(primary_key=True)
    tree = models.ForeignKey(Tree, on_delete=models.PROTECT, verbose_name='样木')
    num = models.CharField(max_length=100, null=False, blank=False, verbose_name="样品编号")

    FW = models.FloatField(null=True, verbose_name='鲜重')
    DW = models.FloatField(null=True, verbose_name='干重')

    time = models.DateField(null=True, verbose_name="取样时间", )
    remark = models.CharField(max_length=500, null=True, verbose_name="备注")

    class Meta:
        db_table = 'tree_sample'


class TreeSampleSerializer(serializers.ModelSerializer):
    tree_num = serializers.SerializerMethodField('get_tree_num')
    WC = serializers.SerializerMethodField()  # 含水率 Water Content

    class Meta:
        model = TreeSample
        fields = '__all__'

    def get_tree_num(self, obj):
        # 拼接地址、树种和样木编号
        address = obj.tree.address.id if obj.tree.address else ''
        treeSpecies = obj.tree.treeSpecies.id if obj.tree.treeSpecies else ''
        number = obj.tree.number if obj.tree.number else ''

        return f"{address}-{treeSpecies}-{number}"

    def get_WC(self, obj):
        # 计算含水率
        fw = obj.FW
        dw = obj.DW

        return 1 - dw / fw
